using Microsoft.AspNetCore.Http;
using Minio;
using Minio.DataModel.Args;
using Minio.Exceptions;
using System.Security.Cryptography;
using System.Text;

namespace SupplierCustomerManagement.Write.API.Services
{
    /// <summary>
    /// MinIO服务实现
    /// </summary>
    public class MinioService : IMinioService
    {
        private readonly IMinioClient _minioClient;
        private readonly ILogger<MinioService> _logger;
        private readonly string _endpoint;
        private readonly string _accessKey;
        private readonly string _secretKey;

        public MinioService(IConfiguration configuration, ILogger<MinioService> logger)
        {
            _logger = logger;
            _endpoint = configuration["MinIO:Endpoint"] ?? "localhost:9000";
            _accessKey = configuration["MinIO:AccessKey"] ?? "minioadmin";
            _secretKey = configuration["MinIO:SecretKey"] ?? "minioadmin";

            _minioClient = new MinioClient()
                .WithEndpoint(_endpoint)
                .WithCredentials(_accessKey, _secretKey)
                .WithSSL(false) // 根据实际情况配置
                .Build();
        }

        /// <summary>
        /// 上传文件到MinIO
        /// </summary>
        /// <param name="file">要上传的文件</param>
        /// <param name="bucketName">存储桶名称</param>
        /// <param name="objectName">对象名称</param>
        /// <returns>文件访问URL</returns>
        public async Task<string> UploadFileAsync(IFormFile file, string bucketName, string objectName)
        {
            try
            {
                _logger.LogInformation("开始上传文件到MinIO，文件名：{FileName}，存储桶：{BucketName}，对象名：{ObjectName}",
                    file.FileName, bucketName, objectName);

                // 确保存储桶存在
                await EnsureBucketExistsAsync(bucketName);

                // 上传文件
                var putObjectArgs = new PutObjectArgs()
                    .WithBucket(bucketName)
                    .WithObject(objectName)
                    .WithStreamData(file.OpenReadStream())
                    .WithObjectSize(file.Length)
                    .WithContentType(file.ContentType);

                await _minioClient.PutObjectAsync(putObjectArgs);

                // 生成访问URL
                var url = await GetPresignedUrlAsync(bucketName, objectName);

                _logger.LogInformation("文件上传成功，访问URL：{Url}", url);

                return url;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "文件上传失败，文件名：{FileName}，存储桶：{BucketName}，对象名：{ObjectName}",
                    file.FileName, bucketName, objectName);
                throw;
            }
        }

        /// <summary>
        /// 检查存储桶是否存在，不存在则创建
        /// </summary>
        /// <param name="bucketName">存储桶名称</param>
        /// <returns>是否存在</returns>
        public async Task<bool> EnsureBucketExistsAsync(string bucketName)
        {
            try
            {
                var bucketExistsArgs = new BucketExistsArgs().WithBucket(bucketName);
                bool found = await _minioClient.BucketExistsAsync(bucketExistsArgs);

                if (!found)
                {
                    _logger.LogInformation("存储桶不存在，正在创建存储桶：{BucketName}", bucketName);
                    var makeBucketArgs = new MakeBucketArgs().WithBucket(bucketName);
                    await _minioClient.MakeBucketAsync(makeBucketArgs);

                    // 设置存储桶为公开读取
                    var policy = $@"{{
                        ""Version"": ""2012-10-17"",
                        ""Statement"": [
                            {{
                                ""Effect"": ""Allow"",
                                ""Principal"": {{""AWS"": [""*""]}},
                                ""Action"": [""s3:GetObject""],
                                ""Resource"": [""arn:aws:s3:::{bucketName}/*""]
                            }}
                        ]
                    }}";

                    var setPolicyArgs = new SetPolicyArgs().WithBucket(bucketName).WithPolicy(policy);
                    await _minioClient.SetPolicyAsync(setPolicyArgs);

                    _logger.LogInformation("存储桶创建成功：{BucketName}", bucketName);
                }

                return true;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "检查或创建存储桶失败：{BucketName}", bucketName);
                throw;
            }
        }

        /// <summary>
        /// 删除文件
        /// </summary>
        /// <param name="bucketName">存储桶名称</param>
        /// <param name="objectName">对象名称</param>
        /// <returns>是否删除成功</returns>
        public async Task<bool> DeleteFileAsync(string bucketName, string objectName)
        {
            try
            {
                _logger.LogInformation("开始删除文件，存储桶：{BucketName}，对象名：{ObjectName}", bucketName, objectName);

                var removeObjectArgs = new RemoveObjectArgs().WithBucket(bucketName).WithObject(objectName);
                await _minioClient.RemoveObjectAsync(removeObjectArgs);

                _logger.LogInformation("文件删除成功，存储桶：{BucketName}，对象名：{ObjectName}", bucketName, objectName);
                return true;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "文件删除失败，存储桶：{BucketName}，对象名：{ObjectName}", bucketName, objectName);
                return false;
            }
        }

        /// <summary>
        /// 获取文件访问URL
        /// </summary>
        /// <param name="bucketName">存储桶名称</param>
        /// <param name="objectName">对象名称</param>
        /// <param name="expiresInSeconds">过期时间（秒）</param>
        /// <returns>预签名URL</returns>
        public async Task<string> GetPresignedUrlAsync(string bucketName, string objectName, int expiresInSeconds = 7 * 24 * 3600)
        {
            try
            {
                var presignedGetObjectArgs = new PresignedGetObjectArgs()
                    .WithBucket(bucketName)
                    .WithObject(objectName)
                    .WithExpiry(expiresInSeconds);

                var url = await _minioClient.PresignedGetObjectAsync(presignedGetObjectArgs);
                return url;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "获取预签名URL失败，存储桶：{BucketName}，对象名：{ObjectName}", bucketName, objectName);
                throw;
            }
        }

        /// <summary>
        /// 生成唯一文件名
        /// </summary>
        /// <param name="originalFileName">原始文件名</param>
        /// <returns>唯一文件名</returns>
        public static string GenerateUniqueFileName(string originalFileName)
        {
            var extension = Path.GetExtension(originalFileName);
            var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(originalFileName);
            var timestamp = DateTime.Now.ToString("yyyyMMddHHmmss");
            var randomString = Convert.ToBase64String(Guid.NewGuid().ToByteArray())
                .Replace("/", "").Replace("+", "").Replace("=", "")
                .Substring(0, 8);

            return $"{fileNameWithoutExtension}_{timestamp}_{randomString}{extension}";
        }
    }
}